package com.beiding.aggregationcloaddloer;

import java.io.IOException;
import java.net.URL;
import java.util.*;

/*
    聚合类加载器


 */
public class AggregationClassloader extends ClassLoader {

    private ClassLoader parent;

    ResourceProvider resourceProvider = new ResourceProvider() {
        @Override
        public URL findResource(String name) {
            if (parent != null) {
                return parent.getResource(name);
            }
            return AggregationClassloader.super.findResource(name);
        }

        @Override
        public Enumeration<URL> findResources(String name) throws IOException {
            if (parent != null) {
                return parent.getResources(name);
            }
            return AggregationClassloader.super.findResources(name);
        }
    };

    public AggregationClassloader() {
        super(null);
    }

    public void setParent(ClassLoader parent) {
        this.parent = parent;
    }

    public void setResourceProvider(ResourceProvider resourceProvider) {
        resourceProvider.getClass();
        this.resourceProvider = resourceProvider;
    }

    //销毁一个类,返回销毁时下游类
/*
    Set<Class> destroyClass(Class c) {
    }

    //重载一个类,返回所有相关的下游类的变化
    Set<ClassChange> reloadClass(Class c) {
    }
*/

    @Override
    public Class<?> loadClass(String name) throws ClassNotFoundException {

        if (parent != null) {

            //尝试使用父类加载器进行加载

            try {
                Class<?> loadClass = parent.loadClass(name);
                if (loadClass != null) {
                    return loadClass;
                }
            } catch (ClassNotFoundException ignore) {

            }
        }

        return controlLoad(name);

    }

    Map<String, Class> loadedClasses = new HashMap<>();

    Class<?> controlLoad(String name) throws ClassNotFoundException {

        Class aClass = loadedClasses.get(name);

        if (aClass == null) {
            synchronized (this) {
                if ((aClass = loadedClasses.get(name)) == null) {
                    aClass = new SingleClassloader(AggregationClassloader.this, name).loadClass(name);
                    loadedClasses.put(name, aClass);
                }
            }
        }

        return aClass;

    }

    public static Set<Class> destroy(Class c) {
        ClassLoader classLoader = c.getClassLoader();
        if (!(classLoader instanceof SingleClassloader)) {
            return Collections.EMPTY_SET;
        }

        Set<Class> r = new HashSet<>();
        ((SingleClassloader) classLoader).destroy(r);
        return r;
    }

    //重定义类
    public static Map<Class, Class> reload(Class c) throws ClassNotFoundException {
        Set<Class> destroy = destroy(c);
        if (destroy.size() == 0) {
            return Collections.EMPTY_MAP;
        }

        AggregationClassloader aggregationClassloader = ((SingleClassloader) c.getClassLoader()).aggregationClassloader;

        aggregationClassloader.controlLoad(c.getName());

        Map<Class, Class> changes = new HashMap<>();

        for (Class aClass : destroy) {
            changes.put(aClass, aggregationClassloader.loadClass(aClass.getName()));
        }

        return changes;

    }

}
